package pl.droidsonroids.gif;

import ohos.aafwk.ability.DataAbilityHelper;
import ohos.aafwk.ability.DataAbilityRemoteException;
import ohos.global.resource.NotExistException;
import ohos.global.resource.RawFileDescriptor;
import ohos.global.resource.RawFileEntry;
import ohos.global.resource.ResourceManager;
import ohos.global.resource.WrongTypeException;
import ohos.utils.net.Uri;

import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.concurrent.ScheduledThreadPoolExecutor;

/**
 * Abstract class for all input sources, to be used with {@link GifTextureView}
 */
public abstract class InputSource {
    private InputSource() {
    }

    abstract GifInfoHandle open() throws IOException, DataAbilityRemoteException;

    final GifDrawable createGifDrawable(final GifDrawable oldDrawable, final ScheduledThreadPoolExecutor executor,
    final boolean isRenderingAlwaysEnabled, final GifOptions options) throws IOException, DataAbilityRemoteException {
        return new GifDrawable(createHandleWith(options), oldDrawable, executor, isRenderingAlwaysEnabled);
    }

    final GifInfoHandle createHandleWith(GifOptions options) throws IOException, DataAbilityRemoteException {
        final GifInfoHandle handle = open();
        handle.setOptions(options.inSampleSize, options.inIsOpaque);
        return handle;
    }

    /**
     * Input using {@link ByteBuffer} as a source. It must be direct.
     */
    public static final class DirectByteBufferSource extends InputSource {
        private final ByteBuffer byteBuffer;

        /**
         * Constructs new source.
         * Buffer can be larger than size of the GIF data. Bytes beyond GIF terminator are not accessed.
         *
         * @param byteBuffer source buffer, must be direct
         */
        public DirectByteBufferSource(ByteBuffer byteBuffer) {
            this.byteBuffer = byteBuffer;
        }

        @Override
        GifInfoHandle open() throws GifIOException {
            return new GifInfoHandle(byteBuffer);
        }
    }

    /**
     * Input using byte array as a source.
     */
    public static final class ByteArraySource extends InputSource {
        private final byte[] bytes;

        /**
         * Constructs new source.
         * Array can be larger than size of the GIF data. Bytes beyond GIF terminator are not accessed.
         *
         * @param bytes source array
         */
        public ByteArraySource(byte[] bytes) {
            this.bytes = bytes;
        }

        @Override
        GifInfoHandle open() throws GifIOException {
            return new GifInfoHandle(bytes);
        }
    }

    /**
     * Input using {@link File} or path as source.
     */
    public static final class FileSource extends InputSource {
        private final String mPath;

        /**
         * Constructs new source.
         *
         * @param file source file
         */
        public FileSource(File file) {
            mPath = file.getPath();
        }

        /**
         * Constructs new source.
         *
         * @param filePath source file path
         */
        public FileSource(String filePath) {
            mPath = filePath;
        }

        @Override
        GifInfoHandle open() throws GifIOException {
            return new GifInfoHandle(mPath);
        }
    }

    /**
     * UriSource
     */
    public static final class UriSource extends InputSource {
        private final DataAbilityHelper mContentResolver;
        private final Uri mUri;

        /**
         * Uri source
         * @param dataAbilityHelper DataAbilityHelper
         * @param uri uri
         */
        public UriSource(DataAbilityHelper dataAbilityHelper, Uri uri) {
            mContentResolver = dataAbilityHelper;
            mUri = uri;
        }

        @Override
        GifInfoHandle open() throws IOException, DataAbilityRemoteException {
            return GifInfoHandle.openUri(mContentResolver, mUri);
        }
    }

    /**
     * Input using openharmony asset as source.
     */
    public static final class AssetSource extends InputSource {
        private final RawFileEntry mAssetManager;
        private final String mAssetName;

        public AssetSource(RawFileEntry rawFileEntry, String assetName) {
            mAssetManager = rawFileEntry;
            mAssetName = assetName;
        }

        @Override
        GifInfoHandle open() throws IOException {
            return new GifInfoHandle(mAssetManager.openRawFileDescriptor());
        }
    }

    /**
     * Input using {@link FileDescriptor} as a source.
     */
    public static final class FileDescriptorSource extends InputSource {
        private final FileDescriptor mFd;

        /**
         * Constructs new source.
         *
         * @param fileDescriptor source file descriptor
         */
        public FileDescriptorSource(FileDescriptor fileDescriptor) {
            mFd = fileDescriptor;
        }

        @Override
        GifInfoHandle open() throws IOException {
            return new GifInfoHandle(mFd);
        }
    }

    /**
     * Input using {@link InputStream} as a source.
     */
    public static final class InputStreamSource extends InputSource {
        private final InputStream inputStream;

        /**
         * Constructs new source.
         *
         * @param inputStream source input stream, it must support marking
         */
        public InputStreamSource(InputStream inputStream) {
            this.inputStream = inputStream;
        }

        @Override
        GifInfoHandle open() throws IOException {
            return new GifInfoHandle(inputStream);
        }
    }

    /**
     * Input using openharmony resource (raw or drawable) as a source.
     */
    public static class ResourcesSource extends InputSource {
        private final ResourceManager mResources;
        private final int mResourceId;

        /**
         * Constructor
         */
        public ResourcesSource(ResourceManager resources, int resourceId) {
            mResources = resources;
            mResourceId = resourceId;
        }

        @Override
        GifInfoHandle open() throws IOException {
            String path = null;
            try {
                path = mResources.getMediaPath(mResourceId);
            } catch (NotExistException e) {
                e.printStackTrace();
            } catch (WrongTypeException e) {
                e.printStackTrace();
            }
            return new GifInfoHandle(mResources.getRawFileEntry(path).openRawFileDescriptor());
        }
    }

    /**
     * AssetFileDescriptorSource
     */
    public static class AssetFileDescriptorSource extends InputSource {
        private final RawFileDescriptor mRawFileDescriptor;

        public AssetFileDescriptorSource(RawFileDescriptor rawFileDescriptor) {
            mRawFileDescriptor = rawFileDescriptor;
        }

        @Override
        GifInfoHandle open() throws IOException {
            return new GifInfoHandle(mRawFileDescriptor);
        }
    }
}
